

<!DOCTYPE html>
<html lang="en" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.png">
  <link rel="icon" href="/img/avatar.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="Hughie">
  <meta name="keywords" content="">
  
    <meta name="description" content="JVM学习记录本博客是根据黑马程序员JVM完整教程学习时做的笔记 一、关于JVM1. 什么是JVM定义：Java Virtual Machine - java 程序的运行环境（java 二进制字节码的运行环境） 好处： 一次编写，到处运行 自动内存管理，垃圾回收功能 数组下标越界检查 多态 比较 JVM JRE JDK的区别  2. 常见的 JVM 二、内存结构整体架构其中程序计数器、虚拟机栈、本">
<meta property="og:type" content="article">
<meta property="og:title" content="JVM">
<meta property="og:url" content="https://hughie-hy.gitee.io/2022/02/26/JVM%E7%AC%94%E8%AE%B0/index.html">
<meta property="og:site_name" content="Hughie&#39;s blog">
<meta property="og:description" content="JVM学习记录本博客是根据黑马程序员JVM完整教程学习时做的笔记 一、关于JVM1. 什么是JVM定义：Java Virtual Machine - java 程序的运行环境（java 二进制字节码的运行环境） 好处： 一次编写，到处运行 自动内存管理，垃圾回收功能 数组下标越界检查 多态 比较 JVM JRE JDK的区别  2. 常见的 JVM 二、内存结构整体架构其中程序计数器、虚拟机栈、本">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="https://hughie-hy.gitee.io/img/java.png">
<meta property="article:published_time" content="2022-02-26T02:28:35.000Z">
<meta property="article:modified_time" content="2022-03-03T13:24:30.187Z">
<meta property="article:author" content="Hughie">
<meta property="article:tag" content="JVM">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://hughie-hy.gitee.io/img/java.png">
  
  
  <title>JVM - Hughie&#39;s blog</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4/github-markdown.min.css" />
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hint.css@2/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10/styles/github.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.css" />
  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"hughie-hy.gitee.io","root":"/","version":"1.8.14","typing":{"enable":true,"typeSpeed":120,"cursorChar":"_","loop":false},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.4.1"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>Hughie</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                Home
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                Archives
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                Categories
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                Tags
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                About
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/img/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="JVM">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2022-02-26 10:28" pubdate>
        February 26, 2022 am
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      18k 字
    </span>
  

  
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      153 分钟
    </span>
  

  
  
    
      <!-- 不蒜子统计文章PV -->
      <span id="busuanzi_container_page_pv" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="busuanzi_value_page_pv"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">JVM</h1>
            
            <div class="markdown-body">
              <h2 id="JVM学习记录"><a href="#JVM学习记录" class="headerlink" title="JVM学习记录"></a>JVM学习记录</h2><p>本博客是根据<a target="_blank" rel="noopener" href="https://www.bilibili.com/video/av70549061?from=search&seid=15623103346123648988&spm_id_from=333.337.0.0">黑马程序员JVM完整教程</a>学习时做的笔记</p>
<h2 id="一、关于JVM"><a href="#一、关于JVM" class="headerlink" title="一、关于JVM"></a>一、关于JVM</h2><h3 id="1-什么是JVM"><a href="#1-什么是JVM" class="headerlink" title="1. 什么是JVM"></a>1. 什么是JVM</h3><p><strong>定义</strong>：Java Virtual Machine - java 程序的运行环境（java 二进制字节码的运行环境）</p>
<p>好处：</p>
<p>一次编写，到处运行</p>
<p>自动内存管理，垃圾回收功能</p>
<p>数组下标越界检查</p>
<p>多态</p>
<p><strong>比较</strong></p>
<p>JVM JRE JDK的区别</p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/static20200608150422.png" srcset="/img/loading.gif" lazyload></p>
<h3 id="2-常见的-JVM"><a href="#2-常见的-JVM" class="headerlink" title="2. 常见的 JVM"></a>2. 常见的 JVM</h3><p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/staticimage-20220226145046008.png" srcset="/img/loading.gif" lazyload></p>
<h2 id="二、内存结构"><a href="#二、内存结构" class="headerlink" title="二、内存结构"></a>二、内存结构</h2><h3 id="整体架构"><a href="#整体架构" class="headerlink" title="整体架构"></a><strong>整体架构</strong></h3><p>其中程序计数器、虚拟机栈、本地方法栈均为线程私有</p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/staticimage-20220226150641763.png" srcset="/img/loading.gif" lazyload></p>
<h3 id="1-程序计数器"><a href="#1-程序计数器" class="headerlink" title="1. 程序计数器"></a>1. 程序计数器</h3><h4 id="作用"><a href="#作用" class="headerlink" title="作用"></a>作用</h4><p>用于保存JVM中下一条所要执行的指令的地址</p>
<h4 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h4><ul>
<li>线程私有<ul>
<li>CPU会为每个线程分配时间片，当当前线程的时间片使用完以后，CPU就会去执行另一个线程中的代码</li>
<li>程序计数器是<strong>每个线程</strong>所<strong>私有</strong>的，当另一个线程的时间片用完，又返回来执行当前线程的代码时，通过程序计数器可以知道应该执行哪一句指令</li>
</ul>
</li>
<li>不会存在内存溢出</li>
</ul>
<h3 id="2-虚拟机栈"><a href="#2-虚拟机栈" class="headerlink" title="2. 虚拟机栈"></a>2. 虚拟机栈</h3><h4 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h4><ul>
<li><p>每个<strong>线程</strong>运行需要的内存空间，称为<strong>虚拟机栈</strong></p>
</li>
<li><p>每个栈由多个<strong>栈帧</strong>组成，对应着每次调用方法时所占用的内存</p>
</li>
<li><p>每个线程只能有<strong>一个活动栈帧</strong>，对应着<strong>当前正在执行的方法</strong></p>
<p>注：每当启用一个线程时，JVM就为他分配一个Java栈，栈是以帧为单位保存当前线程的运行状态。</p>
</li>
</ul>
<h4 id="问题辨析"><a href="#问题辨析" class="headerlink" title="问题辨析"></a>问题辨析</h4><ul>
<li>垃圾回收是否涉及栈内存？<ul>
<li><strong>不需要</strong>。因为虚拟机栈中是由一个个栈帧组成的，在方法执行完毕后，对应的栈帧就会被弹出栈。所以无需通过垃圾回收机制去回收内存。</li>
</ul>
</li>
<li>栈内存的分配越大越好吗？<ul>
<li>不是。因为<strong>物理内存是一定的</strong>，栈内存越大，可以支持更多的递归调用，但是可执行的线程数就会越少。</li>
</ul>
</li>
<li>方法内的局部变量是否是线程安全的？<ul>
<li>如果方法内<strong>局部变量没有逃离方法的作用范围</strong>，则是<strong>线程安全</strong>的</li>
<li>如果如果<strong>局部变量引用了对象</strong>，并<strong>逃离了方法的作用范围</strong>，则需要考虑线程安全问题</li>
</ul>
</li>
</ul>
<h4 id="内存溢出"><a href="#内存溢出" class="headerlink" title="内存溢出"></a>内存溢出</h4><p><strong>Java.lang.stackOverflowError</strong> 栈内存溢出</p>
<p><strong>发生原因</strong></p>
<ul>
<li>虚拟机栈中，<strong>栈帧过多</strong>（无限递归）</li>
<li>每个栈帧<strong>所占用过大</strong></li>
</ul>
<h4 id="线程运行诊断"><a href="#线程运行诊断" class="headerlink" title="线程运行诊断"></a>线程运行诊断</h4><p>CPU占用过高</p>
<ul>
<li>Linux环境下运行某些程序的时候，可能导致CPU的占用过高，这时需要定位占用CPU过高的线程<ul>
<li><strong>top</strong>命令，查看是哪个<strong>进程</strong>占用CPU过高</li>
<li><strong>ps H -eo pid, tid（线程id）, %cpu | grep 刚才通过top查到的进程号</strong> 通过ps命令进一步查看是哪个线程占用CPU过高</li>
<li><strong>jstack 进程id</strong> 通过查看进程中的线程的nid，刚才通过ps命令看到的tid来<strong>对比定位</strong>，注意jstack查找出的线程id是<strong>16进制的</strong>，<strong>需要转换</strong></li>
</ul>
</li>
</ul>
<h3 id="3-本地方法栈"><a href="#3-本地方法栈" class="headerlink" title="3. 本地方法栈"></a>3. 本地方法栈</h3><p>一些带有<strong>native关键字</strong>的方法就是需要JAVA去调用本地的C或者C++方法，因为JAVA有时候没法直接和操作系统底层交互，所以需要用到本地方法</p>
<h3 id="4-堆"><a href="#4-堆" class="headerlink" title="4. 堆"></a>4. 堆</h3><h4 id="定义-1"><a href="#定义-1" class="headerlink" title="定义"></a>定义</h4><p>通过new关键字<strong>创建的对象</strong>都会被放在堆内存</p>
<h4 id="特点-1"><a href="#特点-1" class="headerlink" title="特点"></a>特点</h4><ul>
<li><strong>所有线程共享</strong>，堆内存中的对象都需要<strong>考虑线程安全问题</strong></li>
<li>有垃圾回收机制</li>
</ul>
<h4 id="堆内存溢出"><a href="#堆内存溢出" class="headerlink" title="堆内存溢出"></a>堆内存溢出</h4><p><strong>java.lang.OutofMemoryError</strong> ：java heap space. 堆内存溢出</p>
<h4 id="堆内存诊断"><a href="#堆内存诊断" class="headerlink" title="堆内存诊断"></a>堆内存诊断</h4><p><strong>jps</strong></p>
<p><strong>jmap</strong></p>
<p><strong>jconsole</strong></p>
<p><strong>jvirsalvm</strong></p>
<h3 id="5-方法区"><a href="#5-方法区" class="headerlink" title="5. 方法区"></a>5. 方法区</h3><h4 id="结构"><a href="#结构" class="headerlink" title="结构"></a>结构</h4><p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/staticimage-20220226151036156.png" srcset="/img/loading.gif" lazyload></p>
<h4 id="内存溢出-1"><a href="#内存溢出-1" class="headerlink" title="内存溢出"></a>内存溢出</h4><ul>
<li>1.8以前会导致<strong>永久代</strong>内存溢出</li>
<li>1.8以后会导致<strong>元空间</strong>内存溢出</li>
</ul>
<h4 id="常量池"><a href="#常量池" class="headerlink" title="常量池"></a>常量池</h4><p>二进制字节码的组成：类的基本信息、常量池、类的方法定义（包含了虚拟机指令）</p>
<p><strong>通过反编译来查看类的信息</strong></p>
<ul>
<li><p>获得对应类的.class文件</p>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java">javac -filename.java<br></code></pre></div></td></tr></table></figure>

<p>输入完成后，对应的目录下就会出现类的.class文件</p>
</li>
<li><p>在控制台输入 javap -v 类的绝对路径</p>
<figure class="highlight applescript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs applescript">javap -v filename.<span class="hljs-built_in">class</span><br></code></pre></div></td></tr></table></figure>
</li>
<li><p>然后能在控制台看到反编译以后类的信息了</p>
<ul>
<li><p>类的基本信息</p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/staticimage-20220226152959824.png" srcset="/img/loading.gif" lazyload></p>
</li>
<li><p>常量池</p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/staticimage-20220226153108741.png" srcset="/img/loading.gif" lazyload></p>
<p>虚拟机中按照指令执行编译的方法（#号的内容需要在常量池中查找)</p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/staticimage-20220226153229392.png" srcset="/img/loading.gif" lazyload></p>
</li>
</ul>
</li>
</ul>
<h4 id="运行时常量池"><a href="#运行时常量池" class="headerlink" title="运行时常量池"></a>运行时常量池</h4><ul>
<li>常量池<ul>
<li>就是一张表（如上图中的constant pool），虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量信息</li>
</ul>
</li>
<li>运行时常量池<ul>
<li>常量池是*.class文件中的，当该<strong>类被加载以后</strong>，它的常量池信息就会<strong>放入运行时常量池</strong>，并把里面的<strong>符号地址变为真实地址</strong></li>
</ul>
</li>
</ul>
<h4 id="常量池与串池的关系"><a href="#常量池与串池的关系" class="headerlink" title="常量池与串池的关系"></a>常量池与串池的关系</h4><h5 id="串池StringTable"><a href="#串池StringTable" class="headerlink" title="串池StringTable"></a><strong>串池</strong>StringTable</h5><p><strong>特征</strong></p>
<ul>
<li>常量池中的字符串仅是符号，只有<strong>在被用到时才会转化为对象</strong></li>
<li>利用串池的机制，来避免重复创建字符串对象</li>
<li>字符串<strong>变量</strong>拼接的原理是<strong>StringBuilder</strong></li>
<li>字符串<strong>常量</strong>拼接的原理是<strong>编译器优化</strong></li>
<li>可以使用<strong>intern方法</strong>，主动将串池中还没有的字符串对象放入串池中</li>
<li><strong>注意</strong>：无论是串池还是堆里面的字符串，都是对象</li>
</ul>
<p>用来放字符串对象且里面的<strong>元素不重复</strong></p>
<figure class="highlight typescript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs typescript"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">StringTableStudy</span> &#123;<br>	<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">main</span>(<span class="hljs-params"><span class="hljs-built_in">String</span>[] args</span>) &#123;<br>		<span class="hljs-title class_">String</span> a = <span class="hljs-string">&quot;a&quot;</span>; <br>		<span class="hljs-title class_">String</span> b = <span class="hljs-string">&quot;b&quot;</span>;<br>		<span class="hljs-title class_">String</span> ab = <span class="hljs-string">&quot;ab&quot;</span>;<br>	&#125;<br>&#125;<span class="hljs-title class_">Copy</span><br></code></pre></div></td></tr></table></figure>

<p>常量池中的信息，都会被加载到运行时常量池中，但这是a b ab 仅是常量池中的符号，<strong>还没有成为java字符串</strong></p>
<figure class="highlight ldif"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs ldif"><span class="hljs-attribute">0</span>: ldc           <span class="hljs-comment">#2                  // String a</span><br><span class="hljs-attribute">2</span>: astore_1<br><span class="hljs-attribute">3</span>: ldc           <span class="hljs-comment">#3                  // String b</span><br><span class="hljs-attribute">5</span>: astore_2<br><span class="hljs-attribute">6</span>: ldc           <span class="hljs-comment">#4                  // String ab</span><br><span class="hljs-attribute">8</span>: astore_3<br><span class="hljs-attribute">9</span>: returnCopy<br></code></pre></div></td></tr></table></figure>

<p>当执行到 ldc #2 时，会把符号 a 变为 “a” 字符串对象，<strong>并放入串池中</strong>（hashtable结构 不可扩容）</p>
<p>当执行到 ldc #3 时，会把符号 b 变为 “b” 字符串对象，并放入串池中</p>
<p>当执行到 ldc #4 时，会把符号 ab 变为 “ab” 字符串对象，并放入串池中</p>
<p>最终<strong>StringTable [“a”, “b”, “ab”]</strong></p>
<p><strong>注意</strong>：字符串对象的创建都是<strong>懒惰的</strong>，只有当运行到那一行字符串且在串池中不存在的时候（如 ldc #2）时，该字符串才会被创建并放入串池中。</p>
<p>使用拼接<strong>字符串变量对象</strong>创建字符串的过程</p>
<figure class="highlight typescript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs typescript"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">StringTableStudy</span> &#123;<br>	<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">main</span>(<span class="hljs-params"><span class="hljs-built_in">String</span>[] args</span>) &#123;<br>		<span class="hljs-title class_">String</span> a = <span class="hljs-string">&quot;a&quot;</span>;<br>		<span class="hljs-title class_">String</span> b = <span class="hljs-string">&quot;b&quot;</span>;<br>		<span class="hljs-title class_">String</span> ab = <span class="hljs-string">&quot;ab&quot;</span>;<br>		<span class="hljs-comment">//拼接字符串对象来创建新的字符串</span><br>		<span class="hljs-title class_">String</span> ab2 = a+b; <br>	&#125;<br>&#125;<span class="hljs-title class_">Copy</span><br></code></pre></div></td></tr></table></figure>

<p>反编译后的结果</p>
<figure class="highlight yaml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs yaml">	 <span class="hljs-attr">Code:</span><br>      <span class="hljs-string">stack=2,</span> <span class="hljs-string">locals=5,</span> <span class="hljs-string">args_size=1</span><br>         <span class="hljs-attr">0:</span> <span class="hljs-string">ldc</span>           <span class="hljs-comment">#2                  // String a</span><br>         <span class="hljs-attr">2:</span> <span class="hljs-string">astore_1</span><br>         <span class="hljs-attr">3:</span> <span class="hljs-string">ldc</span>           <span class="hljs-comment">#3                  // String b</span><br>         <span class="hljs-attr">5:</span> <span class="hljs-string">astore_2</span><br>         <span class="hljs-attr">6:</span> <span class="hljs-string">ldc</span>           <span class="hljs-comment">#4                  // String ab</span><br>         <span class="hljs-attr">8:</span> <span class="hljs-string">astore_3</span><br>         <span class="hljs-attr">9:</span> <span class="hljs-string">new</span>           <span class="hljs-comment">#5                  // class java/lang/StringBuilder</span><br>        <span class="hljs-attr">12:</span> <span class="hljs-string">dup</span><br>        <span class="hljs-attr">13:</span> <span class="hljs-string">invokespecial</span> <span class="hljs-comment">#6                  // Method java/lang/StringBuilder.&quot;&lt;init&gt;&quot;:()V</span><br>        <span class="hljs-attr">16:</span> <span class="hljs-string">aload_1</span><br>        <span class="hljs-attr">17:</span> <span class="hljs-string">invokevirtual</span> <span class="hljs-comment">#7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String</span><br><span class="hljs-string">;)Ljava/lang/StringBuilder;</span><br>        <span class="hljs-attr">20:</span> <span class="hljs-string">aload_2</span><br>        <span class="hljs-attr">21:</span> <span class="hljs-string">invokevirtual</span> <span class="hljs-comment">#7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String</span><br><span class="hljs-string">;)Ljava/lang/StringBuilder;</span><br>        <span class="hljs-attr">24:</span> <span class="hljs-string">invokevirtual</span> <span class="hljs-comment">#8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/Str</span><br><span class="hljs-string">ing;</span><br>        <span class="hljs-attr">27:</span> <span class="hljs-string">astore</span>        <span class="hljs-number">4</span><br>        <span class="hljs-attr">29:</span> <span class="hljs-string">returnCopy</span><br></code></pre></div></td></tr></table></figure>

<p>通过拼接的方式来创建字符串的<strong>过程</strong>是：StringBuilder().append(“a”).append(“b”).toString()</p>
<p>最后的toString方法的返回值是一个<strong>新的字符串</strong>，但字符串的<strong>值</strong>和拼接的字符串一致，但是两个不同的字符串，<strong>一个存在于串池之中，一个存在于堆内存之中</strong></p>
<figure class="highlight nix"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs nix">String <span class="hljs-attr">ab</span> = <span class="hljs-string">&quot;ab&quot;</span>;<br>String <span class="hljs-attr">ab2</span> = a+b;<br>//结果为<span class="hljs-literal">false</span>,因为ab是存在于串池之中，ab2是由StringBuffer的<span class="hljs-built_in">toString</span>方法所返回的一个对象，存在于堆内存之中<br>System.out.println(<span class="hljs-attr">ab</span> == ab2);Copy<br></code></pre></div></td></tr></table></figure>

<p>使用<strong>拼接字符串常量对象</strong>的方法创建字符串</p>
<figure class="highlight typescript"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs typescript"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">StringTableStudy</span> &#123;<br>	<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">main</span>(<span class="hljs-params"><span class="hljs-built_in">String</span>[] args</span>) &#123;<br>		<span class="hljs-title class_">String</span> a = <span class="hljs-string">&quot;a&quot;</span>;<br>		<span class="hljs-title class_">String</span> b = <span class="hljs-string">&quot;b&quot;</span>;<br>		<span class="hljs-title class_">String</span> ab = <span class="hljs-string">&quot;ab&quot;</span>;<br>		<span class="hljs-title class_">String</span> ab2 = a+b;<br>		<span class="hljs-comment">//使用拼接字符串的方法创建字符串</span><br>		<span class="hljs-title class_">String</span> ab3 = <span class="hljs-string">&quot;a&quot;</span> + <span class="hljs-string">&quot;b&quot;</span>;<br>	&#125;<br>&#125;<span class="hljs-title class_">Copy</span><br></code></pre></div></td></tr></table></figure>

<p>反编译后的结果</p>
<figure class="highlight yaml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs yaml"> 	  <span class="hljs-attr">Code:</span><br>      <span class="hljs-string">stack=2,</span> <span class="hljs-string">locals=6,</span> <span class="hljs-string">args_size=1</span><br>         <span class="hljs-attr">0:</span> <span class="hljs-string">ldc</span>           <span class="hljs-comment">#2                  // String a</span><br>         <span class="hljs-attr">2:</span> <span class="hljs-string">astore_1</span><br>         <span class="hljs-attr">3:</span> <span class="hljs-string">ldc</span>           <span class="hljs-comment">#3                  // String b</span><br>         <span class="hljs-attr">5:</span> <span class="hljs-string">astore_2</span><br>         <span class="hljs-attr">6:</span> <span class="hljs-string">ldc</span>           <span class="hljs-comment">#4                  // String ab</span><br>         <span class="hljs-attr">8:</span> <span class="hljs-string">astore_3</span><br>         <span class="hljs-attr">9:</span> <span class="hljs-string">new</span>           <span class="hljs-comment">#5                  // class java/lang/StringBuilder</span><br>        <span class="hljs-attr">12:</span> <span class="hljs-string">dup</span><br>        <span class="hljs-attr">13:</span> <span class="hljs-string">invokespecial</span> <span class="hljs-comment">#6                  // Method java/lang/StringBuilder.&quot;&lt;init&gt;&quot;:()V</span><br>        <span class="hljs-attr">16:</span> <span class="hljs-string">aload_1</span><br>        <span class="hljs-attr">17:</span> <span class="hljs-string">invokevirtual</span> <span class="hljs-comment">#7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String</span><br><span class="hljs-string">;)Ljava/lang/StringBuilder;</span><br>        <span class="hljs-attr">20:</span> <span class="hljs-string">aload_2</span><br>        <span class="hljs-attr">21:</span> <span class="hljs-string">invokevirtual</span> <span class="hljs-comment">#7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String</span><br><span class="hljs-string">;)Ljava/lang/StringBuilder;</span><br>        <span class="hljs-attr">24:</span> <span class="hljs-string">invokevirtual</span> <span class="hljs-comment">#8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/Str</span><br><span class="hljs-string">ing;</span><br>        <span class="hljs-attr">27:</span> <span class="hljs-string">astore</span>        <span class="hljs-number">4</span><br>        <span class="hljs-string">//ab3初始化时直接从串池中获取字符串</span><br>        <span class="hljs-attr">29:</span> <span class="hljs-string">ldc</span>           <span class="hljs-comment">#4                  // String ab</span><br>        <span class="hljs-attr">31:</span> <span class="hljs-string">astore</span>        <span class="hljs-number">5</span><br>        <span class="hljs-attr">33:</span> <span class="hljs-string">returnCopy</span><br></code></pre></div></td></tr></table></figure>

<ul>
<li>使用<strong>拼接字符串常量</strong>的方法来创建新的字符串时，因为<strong>内容是常量，javac在编译期会进行优化，结果已在编译期确定为ab</strong>，而创建ab的时候已经在串池中放入了“ab”，所以ab3直接从串池中获取值，所以进行的操作和 ab &#x3D; “ab” 一致。</li>
<li>使用<strong>拼接字符串变量</strong>的方法来创建新的字符串时，因为内容是变量，只能<strong>在运行期确定它的值，所以需要使用StringBuilder来创建</strong></li>
</ul>
<h5 id="intern方法-1-8"><a href="#intern方法-1-8" class="headerlink" title="intern方法 1.8"></a>intern方法 1.8</h5><p>调用字符串对象的intern方法，会将该字符串对象尝试放入到串池中</p>
<ul>
<li>如果串池中没有该字符串对象，则放入成功</li>
<li>如果有该字符串对象，则放入失败</li>
</ul>
<p>无论放入是否成功，都会返回<strong>串池中</strong>的字符串对象</p>
<p><strong>注意</strong>：此时如果调用intern方法成功，堆内存与串池中的字符串对象是同一个对象；如果失败，则不是同一个对象</p>
<p><strong>例1</strong></p>
<figure class="highlight processing"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs processing"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Main</span> &#123;<br>	<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span>(<span class="hljs-built_in">String</span>[] args) &#123;<br>		<span class="hljs-comment">//&quot;a&quot; &quot;b&quot; 被放入串池中，str则存在于堆内存之中</span><br>		<span class="hljs-built_in">String</span> <span class="hljs-built_in">str</span> = <span class="hljs-keyword">new </span><span class="hljs-class title_">String</span>(<span class="hljs-string">&quot;a&quot;</span>) + <span class="hljs-keyword">new </span><span class="hljs-class title_">String</span>(<span class="hljs-string">&quot;b&quot;</span>);<br>		<span class="hljs-comment">//调用str的intern方法，这时串池中没有&quot;ab&quot;，则会将该字符串对象放入到串池中，此时堆内存与串池中的&quot;ab&quot;是同一个对象</span><br>		<span class="hljs-built_in">String</span> st2 = <span class="hljs-built_in">str</span>.<span class="hljs-property">intern</span>();<br>		<span class="hljs-comment">//给str3赋值，因为此时串池中已有&quot;ab&quot;，则直接将串池中的内容返回</span><br>		<span class="hljs-built_in">String</span> str3 = <span class="hljs-string">&quot;ab&quot;</span>;<br>		<span class="hljs-comment">//因为堆内存与串池中的&quot;ab&quot;是同一个对象，所以以下两条语句打印的都为true</span><br>		System.<span class="hljs-property">out</span>.<span class="hljs-property">println</span>(<span class="hljs-built_in">str</span> == st2);<br>		System.<span class="hljs-property">out</span>.<span class="hljs-property">println</span>(<span class="hljs-built_in">str</span> == str3);<br>	&#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>

<p><strong>例2</strong></p>
<figure class="highlight pgsql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs pgsql"><span class="hljs-built_in">public</span> <span class="hljs-keyword">class</span> Main &#123;<br>	<span class="hljs-built_in">public</span> static <span class="hljs-type">void</span> main(String[] args) &#123;<br>        //此处创建字符串对象&quot;ab&quot;，因为串池中还没有&quot;ab&quot;，所以将其放入串池中<br>		String str3 = &quot;ab&quot;;<br>        //&quot;a&quot; &quot;b&quot; 被放入串池中，str则存在于堆内存之中<br>		String str = <span class="hljs-built_in">new</span> String(&quot;a&quot;) + <span class="hljs-built_in">new</span> String(&quot;b&quot;);<br>        //此时因为在创建str3时，&quot;ab&quot;已存在与串池中，所以放入失败，但是会返回串池中的&quot;ab&quot;<br>		String str2 = str.intern();<br>        //<span class="hljs-keyword">false</span><br>		<span class="hljs-keyword">System</span>.<span class="hljs-keyword">out</span>.println(str == str2);<br>        //<span class="hljs-keyword">false</span><br>		<span class="hljs-keyword">System</span>.<span class="hljs-keyword">out</span>.println(str == str3);<br>        //<span class="hljs-keyword">true</span><br>		<span class="hljs-keyword">System</span>.<span class="hljs-keyword">out</span>.println(str2 == str3);<br>	&#125;<br>&#125;<br></code></pre></div></td></tr></table></figure>

<h5 id="intern方法-1-6"><a href="#intern方法-1-6" class="headerlink" title="intern方法 1.6"></a>intern方法 1.6</h5><p>调用字符串对象的intern方法，会将该字符串对象尝试放入到串池中</p>
<ul>
<li>如果串池中没有该字符串对象，会将该字符串对象复制一份，再放入到串池中</li>
<li>如果有该字符串对象，则放入失败</li>
</ul>
<p>无论放入是否成功，都会返回<strong>串池中</strong>的字符串对象</p>
<p><strong>注意</strong>：此时无论调用intern方法成功与否，串池中的字符串对象和堆内存中的字符串对象<strong>都不是同一个对象</strong></p>
<h4 id="StringTable-垃圾回收"><a href="#StringTable-垃圾回收" class="headerlink" title="StringTable 垃圾回收"></a>StringTable 垃圾回收</h4><p>StringTable在内存紧张时，会发生垃圾回收</p>
<h4 id="StringTable调优"><a href="#StringTable调优" class="headerlink" title="StringTable调优"></a>StringTable调优</h4><ul>
<li><p>因为StringTable是由HashTable实现的，所以可以<strong>适当增加HashTable桶的个数</strong>，来减少字符串放入串池所需要的时间</p>
<figure class="highlight routeros"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs routeros">-XX:<span class="hljs-attribute">StringTableSize</span>=xxxxCopy<br></code></pre></div></td></tr></table></figure>


</li>
<li><p>考虑是否需要将字符串对象入池</p>
<p>可以通过<strong>intern方法减少重复入池</strong></p>
</li>
</ul>
<h3 id="6-直接内存"><a href="#6-直接内存" class="headerlink" title="6. 直接内存"></a>6. 直接内存</h3><ul>
<li>属于操作系统，常见于NIO操作时，<strong>用于数据缓冲区</strong></li>
<li>分配回收成本较高，但读写性能高</li>
<li>不受JVM内存回收管理</li>
</ul>
<h4 id="文件读写流程"><a href="#文件读写流程" class="headerlink" title="文件读写流程"></a>文件读写流程</h4><p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/image-20220227090356801.png" srcset="/img/loading.gif" lazyload></p>
<p><strong>使用了DirectBuffer</strong></p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/static20200608150736.png" srcset="/img/loading.gif" lazyload></p>
<p>直接内存是操作系统和Java代码<strong>都可以访问的一块区域</strong>，无需将代码从系统内存复制到Java堆内存，从而提高了效率</p>
<h4 id="释放原理"><a href="#释放原理" class="headerlink" title="释放原理"></a>释放原理</h4><p>直接内存的回收不是通过JVM的垃圾回收来释放的，而是通过<strong>unsafe.freeMemory</strong>来手动释放</p>
<p>通过</p>
<figure class="highlight reasonml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs reasonml"><span class="hljs-comment">//通过ByteBuffer申请1M的直接内存</span><br>ByteBuffer byteBuffer = <span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">ByteBuffer</span>.</span></span>allocate<span class="hljs-constructor">Direct(<span class="hljs-params">_1M</span>)</span>;<br></code></pre></div></td></tr></table></figure>

<p>申请直接内存，但JVM并不能回收直接内存中的内容，它是如何实现回收的呢？</p>
<p><strong>allocateDirect的实现</strong></p>
<figure class="highlight arduino"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs arduino"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-type">static</span> ByteBuffer <span class="hljs-title">allocateDirect</span><span class="hljs-params">(<span class="hljs-type">int</span> capacity)</span> </span>&#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">DirectByteBuffer</span>(capacity);<br>&#125;<br></code></pre></div></td></tr></table></figure>

<p>DirectByteBuffer类</p>
<figure class="highlight reasonml"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs reasonml"><span class="hljs-constructor">DirectByteBuffer(<span class="hljs-params">int</span> <span class="hljs-params">cap</span>)</span> &#123;   <span class="hljs-comment">// package-private</span><br>   <br>    super(-<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, cap, cap);<br>    boolean pa = <span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">VM</span>.</span></span>is<span class="hljs-constructor">DirectMemoryPageAligned()</span>;<br>    <span class="hljs-built_in">int</span> ps = <span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">Bits</span>.</span></span>page<span class="hljs-constructor">Size()</span>;<br>    long size = <span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">Math</span>.</span></span>max(<span class="hljs-number">1L</span>, (long)cap + (pa ? ps : <span class="hljs-number">0</span>));<br>    <span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">Bits</span>.</span></span>reserve<span class="hljs-constructor">Memory(<span class="hljs-params">size</span>, <span class="hljs-params">cap</span>)</span>;<br><br>    long base = <span class="hljs-number">0</span>;<br>    <span class="hljs-keyword">try</span> &#123;<br>        base = unsafe.allocate<span class="hljs-constructor">Memory(<span class="hljs-params">size</span>)</span>; <span class="hljs-comment">//申请内存</span><br>    &#125; catch (OutOfMemoryError x) &#123;<br>        <span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">Bits</span>.</span></span>unreserve<span class="hljs-constructor">Memory(<span class="hljs-params">size</span>, <span class="hljs-params">cap</span>)</span>;<br>        throw x;<br>    &#125;<br>    unsafe.set<span class="hljs-constructor">Memory(<span class="hljs-params">base</span>, <span class="hljs-params">size</span>, (<span class="hljs-params">byte</span>)</span> <span class="hljs-number">0</span>);<br>    <span class="hljs-keyword">if</span> (pa<span class="hljs-operator"> &amp;&amp; </span>(base % ps != <span class="hljs-number">0</span>)) &#123;<br>        <span class="hljs-comment">// Round up to page boundary</span><br>        address = base + ps - (base &amp; (ps - <span class="hljs-number">1</span>));<br>    &#125; <span class="hljs-keyword">else</span> &#123;<br>        address = base;<br>    &#125;<br>    cleaner = <span class="hljs-module-access"><span class="hljs-module"><span class="hljs-identifier">Cleaner</span>.</span></span>create(this, <span class="hljs-keyword">new</span> <span class="hljs-constructor">Deallocator(<span class="hljs-params">base</span>, <span class="hljs-params">size</span>, <span class="hljs-params">cap</span>)</span>); <span class="hljs-comment">//通过虚引用，来实现直接内存的释放，this为虚引用的实际对象</span><br>    att = null;<br>&#125;<br></code></pre></div></td></tr></table></figure>

<p>这里调用了一个Cleaner的create方法，且后台线程还会对虚引用的对象监测，如果虚引用的实际对象（这里是DirectByteBuffer）被回收以后，就会调用Cleaner的clean方法，来清除直接内存中占用的内存</p>
<figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">clean</span>()</span> &#123;<br>       <span class="hljs-keyword">if</span> (<span class="hljs-keyword">remove</span>(<span class="hljs-keyword">this</span>)) &#123;<br>           <span class="hljs-keyword">try</span> &#123;<br>               <span class="hljs-keyword">this</span>.thunk.run(); <span class="hljs-comment">//调用run方法</span><br>           &#125; <span class="hljs-keyword">catch</span> (final Throwable var2) &#123;<br>               AccessController.doPrivileged(<span class="hljs-keyword">new</span> PrivilegedAction&lt;Void&gt;() &#123;<br>                   <span class="hljs-function"><span class="hljs-keyword">public</span> Void <span class="hljs-title">run</span>()</span> &#123;<br>                       <span class="hljs-keyword">if</span> (System.err != <span class="hljs-literal">null</span>) &#123;<br>                           (<span class="hljs-keyword">new</span> Error(<span class="hljs-string">&quot;Cleaner terminated abnormally&quot;</span>, var2)).printStackTrace();<br>                       &#125;<br><br>                       System.exit(<span class="hljs-number">1</span>);<br>                       <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>                   &#125;<br>               &#125;);<br>           &#125;Copy<br></code></pre></div></td></tr></table></figure>

<p>对应对象的run方法</p>
<figure class="highlight csharp"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>()</span> &#123;<br>    <span class="hljs-keyword">if</span> (address == <span class="hljs-number">0</span>) &#123;<br>        <span class="hljs-comment">// Paranoia</span><br>        <span class="hljs-keyword">return</span>;<br>    &#125;<br>    <span class="hljs-keyword">unsafe</span>.freeMemory(address); <span class="hljs-comment">//释放直接内存中占用的内存</span><br>    address = <span class="hljs-number">0</span>;<br>    Bits.unreserveMemory(size, capacity);<br>&#125;<br></code></pre></div></td></tr></table></figure>

<h5 id="直接内存的回收机制总结"><a href="#直接内存的回收机制总结" class="headerlink" title="直接内存的回收机制总结"></a>直接内存的回收机制总结</h5><ul>
<li>使用了Unsafe类来完成直接内存的分配回收，回收需要主动调用freeMemory方法</li>
<li>ByteBuffer的实现内部使用了Cleaner（虚引用）来检测ByteBuffer。一旦ByteBuffer被垃圾回收，那么会由ReferenceHandler来调用Cleaner的clean方法调用freeMemory来释放内存</li>
</ul>
<h2 id="三、垃圾回收"><a href="#三、垃圾回收" class="headerlink" title="三、垃圾回收"></a>三、垃圾回收</h2><h3 id="1-如何判断对象可以回收"><a href="#1-如何判断对象可以回收" class="headerlink" title="1. 如何判断对象可以回收"></a>1. 如何判断对象可以回收</h3><h3 id="2-垃圾回收算法"><a href="#2-垃圾回收算法" class="headerlink" title="2. 垃圾回收算法"></a>2. 垃圾回收算法</h3><h3 id="3-分代垃圾回收"><a href="#3-分代垃圾回收" class="headerlink" title="3. 分代垃圾回收"></a>3. 分代垃圾回收</h3><h4 id="3-1-回收流程"><a href="#3-1-回收流程" class="headerlink" title="3.1 回收流程"></a>3.1 回收流程</h4><p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/static3.0.1.png" srcset="/img/loading.gif" lazyload></p>
<p>新创建的对象都被放在了<strong>新生代的eden</strong>中</p>
<p>当伊甸园中的内存不足时，就会进行一次垃圾回收，这时的回收叫做 <strong>Minor GC</strong></p>
<p>Minor GC 会将<strong>伊甸园和幸存区FROM</strong>存活的对象先复制到 <strong>幸存区 TO</strong>中， 并让其<strong>寿命加1</strong>，再<strong>交换两个幸存区</strong></p>
<h4 id="3-2-相关VM参数"><a href="#3-2-相关VM参数" class="headerlink" title="3.2 相关VM参数"></a>3.2 相关VM参数</h4><p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/staticimage-20220226104008448.png" srcset="/img/loading.gif" lazyload alt="image-20220226104008448"></p>
<p>-XX:+UseSerialGC  含义：使用SerialGC幸存区比例不会动态调整 有助于演示</p>
<h4 id="3-3-GC分析"><a href="#3-3-GC分析" class="headerlink" title="3.3 GC分析"></a>3.3 GC分析</h4><h5 id="大对象处理策略"><a href="#大对象处理策略" class="headerlink" title="大对象处理策略"></a>大对象处理策略</h5><p>当遇到一个<strong>较大的对象</strong>时，就算新生代的<strong>eden</strong>为空，也<strong>无法容纳该对象</strong>时，会将该对象直接晋升为老年代</p>
<h5 id="线程内存溢出"><a href="#线程内存溢出" class="headerlink" title="线程内存溢出"></a>线程内存溢出</h5><p>某个线程的内存溢出了而抛异常（out of memory），不会让其他的线程结束运行</p>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">new</span> <span class="hljs-title class_">Thread</span>(()-&gt;&#123;<br>            ArrayList&lt;<span class="hljs-type">byte</span>[]&gt; arrayList = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>            arrayList.add(<span class="hljs-keyword">new</span> <span class="hljs-title class_">byte</span>[_8MB]);<br>            arrayList.add(<span class="hljs-keyword">new</span> <span class="hljs-title class_">byte</span>[_8MB]);<br>        &#125;).start();<br></code></pre></div></td></tr></table></figure>

<p>这是因为当一个线程<strong>抛出OOM异常后</strong>，<strong>它所占据的内存资源会全部被释放掉</strong>，从而不会影响其他线程的运行，进程依然正常</p>
<h3 id="4、垃圾回收器"><a href="#4、垃圾回收器" class="headerlink" title="4、垃圾回收器"></a>4、垃圾回收器</h3><p>串行</p>
<p>吞吐量优先</p>
<p>响应时间优先</p>
<h4 id="4-1-串行"><a href="#4-1-串行" class="headerlink" title="4.1 串行"></a>4.1 串行</h4><ul>
<li>单线程</li>
<li>内存较小，个人电脑（CPU核数较少）</li>
</ul>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/static20200608151027.png" srcset="/img/loading.gif" lazyload></p>
<p><strong>安全点</strong>：让其他线程都在这个点停下来，以免垃圾回收时移动对象地址，使得其他线程找不到被移动的对象</p>
<p>因为是串行的，所以<strong>只有一个垃圾回收线程</strong>。且在该线程执行回收工作时，其他线程进入<strong>阻塞</strong>状态</p>
<h5 id="Serial-GC"><a href="#Serial-GC" class="headerlink" title="Serial GC"></a>Serial GC</h5><p>Serial收集器是最基本的、发展历史最悠久的收集器</p>
<p><strong>特点：</strong>单线程、简单高效（与其他收集器的单线程相比），采用<strong>复制算法</strong>。对于限定单个CPU的环境来说，Serial收集器由于没有线程交互的开销，专心做垃圾收集自然可以获得最高的单线程手机效率。收集器进行垃圾回收时，必须暂停其他所有的工作线程，直到它结束（Stop The World）</p>
<h5 id="SerialOld-GC"><a href="#SerialOld-GC" class="headerlink" title="SerialOld GC"></a>SerialOld GC</h5><p>Serial Old是Serial收集器的老年代版本</p>
<p><strong>特点</strong>：同样是单线程收集器，采用<strong>标记-整理算法</strong></p>
<h4 id="4-2-吞吐量优先"><a href="#4-2-吞吐量优先" class="headerlink" title="4.2 吞吐量优先"></a>4.2 吞吐量优先</h4><ul>
<li>多线程</li>
<li>堆内存较大，多核CPU</li>
<li>单位时间内，STW（stop the world，停掉其他所有工作线程）时间最短</li>
<li><strong>JDK1.8默认使用</strong>的垃圾回收器</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200608151039.png"><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/20200608151039.png" srcset="/img/loading.gif" lazyload></a></p>
<h5 id="Parallel-GC"><a href="#Parallel-GC" class="headerlink" title="Parallel GC"></a>Parallel GC</h5><p>与吞吐量关系密切，故也称为吞吐量优先收集器</p>
<p><strong>特点</strong>：属于新生代收集器也是采用<strong>复制算法</strong>的收集器（用到了新生代的幸存区），又是并行的多线程收集器（与ParNew收集器类似）</p>
<p>该收集器的目标是达到一个可控制的吞吐量。还有一个值得关注的点是：<strong>GC自适应调节策略</strong>（与ParNew收集器最重要的一个区别）</p>
<p><strong>GC自适应调节策略</strong>：Parallel Scavenge收集器可设置-XX:+UseAdptiveSizePolicy参数。当开关打开时<strong>不需要</strong>手动指定新生代的大小（-Xmn）、Eden与Survivor区的比例（-XX:SurvivorRation）、晋升老年代的对象年龄（-XX:PretenureSizeThreshold）等，虚拟机会根据系统的运行状况收集性能监控信息，动态设置这些参数以提供最优的停顿时间和最高的吞吐量，这种调节方式称为GC的自适应调节策略。</p>
<p>Parallel Scavenge收集器使用两个参数控制吞吐量：</p>
<ul>
<li>XX:MaxGCPauseMillis 控制最大的垃圾收集停顿时间</li>
<li>XX:GCRatio 直接设置吞吐量的大小</li>
</ul>
<h5 id="ParallelOld-GC"><a href="#ParallelOld-GC" class="headerlink" title="ParallelOld GC"></a><strong>ParallelOld GC</strong></h5><p>是Parallel Scavenge收集器的老年代版本</p>
<p><strong>特点</strong>：多线程，采用<strong>标记-整理算法</strong>（老年代没有幸存区）</p>
<h4 id="4-3-响应时间优先"><a href="#4-3-响应时间优先" class="headerlink" title="4.3 响应时间优先"></a>4.3 响应时间优先</h4><ul>
<li>多线程</li>
<li>堆内存较大，多核CPU</li>
<li>尽可能让单次STW时间变短（尽量不影响其他线程运行）</li>
</ul>
<p><a target="_blank" rel="noopener" href="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200608151052.png"><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/20200608151052.png" srcset="/img/loading.gif" lazyload></a></p>
<h5 id="CMS-GC"><a href="#CMS-GC" class="headerlink" title="CMS GC"></a>CMS GC</h5><p>Concurrent Mark Sweep，一种以获取<strong>最短回收停顿时间</strong>为目标的<strong>老年代</strong>收集器</p>
<p><strong>特点</strong>：基于<strong>标记-清除算法</strong>实现。并发收集、低停顿，但是会产生内存碎片</p>
<p><strong>应用场景</strong>：适用于注重服务的响应速度，希望系统停顿时间最短，给用户带来更好的体验等场景下。如web程序、b&#x2F;s服务</p>
<p><strong>CMS收集器的运行过程分为下列4步：</strong></p>
<p>初始标记：标记GC Roots能直接到的对象。速度很快但是仍存在Stop The World问题</p>
<p>并发标记：进行GC Roots Tracing 的过程，找出存活对象且用户线程可并发执行    </p>
<p>重新标记：为了<strong>修正并发标记期间</strong>因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录。仍然存在Stop The World问题(改阶段会扫描整个的堆内存包括新生代和老年代)</p>
<p>并发清除：对标记的对象进行清除回收</p>
<p>CMS收集器的内存回收过程是与用户线程一起<strong>并发执行</strong>的</p>
<p><strong>注意</strong>：CMS GC可能导致内存碎片过多而使得并发失败，最终退化为SerialOld</p>
<h5 id="ParNew-GC"><a href="#ParNew-GC" class="headerlink" title="ParNew GC"></a>ParNew GC</h5><p>ParNew收集器其实就是Serial收集器的多线程版本</p>
<p><strong>特点</strong>：多线程、ParNew收集器默认开启的收集线程数与CPU的数量相同，在CPU非常多的环境中，可以使用-XX:ParallelGCThreads参数来限制垃圾收集的线程数。和Serial收集器一样存在Stop The World问题</p>
<h4 id="4-4-G1"><a href="#4-4-G1" class="headerlink" title="4.4 G1"></a>4.4 G1</h4><h5 id="定义："><a href="#定义：" class="headerlink" title="定义："></a><strong>定义</strong>：</h5><p>Garbage First</p>
<p>JDK 9以后默认使用，而且替代了CMS 收集器</p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/image-20220227141800052.png" srcset="/img/loading.gif" lazyload></p>
<h5 id="适用场景"><a href="#适用场景" class="headerlink" title="适用场景"></a>适用场景</h5><ul>
<li>同时注重吞吐量和低延迟（响应时间）</li>
<li>超大堆内存（内存大的），会将堆内存划分为多个<strong>大小相等</strong>的区域</li>
<li>整体上是<strong>标记-整理</strong>算法，两个区域之间是<strong>复制</strong>算法</li>
</ul>
<p><strong>相关参数</strong>：JDK8 并不是默认开启的，所需要参数开启</p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/staticimage-20220226222057235.png" srcset="/img/loading.gif" lazyload></p>
<h5 id="G1垃圾回收阶段"><a href="#G1垃圾回收阶段" class="headerlink" title="G1垃圾回收阶段"></a>G1垃圾回收阶段</h5><p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/staticimage-20220226222130658.png" srcset="/img/loading.gif" lazyload></p>
<p>新生代伊甸园垃圾回收—–&gt;内存不足，新生代回收+并发标记—–&gt;回收新生代伊甸园、幸存区、老年代内存——&gt;新生代伊甸园垃圾回收(重新开始)</p>
<h5 id="Young-Collection"><a href="#Young-Collection" class="headerlink" title="Young Collection"></a>Young Collection</h5><p><strong>分区算法region</strong></p>
<p>分代是按对象的生命周期划分，分区则是将堆空间划分连续几个不同小区间，每一个小区间独立回收，可以控制一次回收多少个小区间，方便控制 GC 产生的停顿时间</p>
<p>E：伊甸园 S：幸存区 O：老年代</p>
<ul>
<li>会STW</li>
</ul>
<p>[<img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/staticimage-20220226222158519.png" srcset="/img/loading.gif" lazyload></p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/staticimage-20220226222232769.png" srcset="/img/loading.gif" lazyload></p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/static20200608151140.png" srcset="/img/loading.gif" lazyload></p>
<h5 id="Young-Collection-CM"><a href="#Young-Collection-CM" class="headerlink" title="Young Collection + CM"></a>Young Collection + CM</h5><p>CM：并发标记</p>
<ul>
<li>在 Young GC 时会<strong>对 GC Root 进行初始标记</strong></li>
<li>在老年代<strong>占用堆内存的比例</strong>达到阈值时，对进行并发标记（不会STW），阈值可以根据用户来进行设定</li>
</ul>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/static20200608151150.png" srcset="/img/loading.gif" lazyload></p>
<h5 id="Mixed-Collection"><a href="#Mixed-Collection" class="headerlink" title="Mixed Collection"></a>Mixed Collection</h5><p>会对E S O 进行<strong>全面的回收</strong></p>
<ul>
<li>最终标记</li>
<li><strong>拷贝</strong>存活</li>
</ul>
<p>-XX:MaxGCPauseMills:xxx 用于指定最长的停顿时间</p>
<p><strong>问</strong>：为什么有的老年代被拷贝了，有的没拷贝？</p>
<p>因为指定了最大停顿时间，如果对所有老年代都进行回收，耗时可能过高。为了保证时间不超过设定的停顿时间，会<strong>回收最有价值的老年代</strong>（回收后，能够得到更多内存）</p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/static20200608151201.png" srcset="/img/loading.gif" lazyload></p>
<p>G1在老年代内存不足时（老年代所占内存超过阈值）</p>
<ul>
<li>如果垃圾产生速度慢于垃圾回收速度，不会触发Full GC，还是并发地进行清理</li>
<li>如果垃圾产生速度快于垃圾回收速度，便会触发Full GC</li>
</ul>
<h5 id="Young-Collection-跨代引用"><a href="#Young-Collection-跨代引用" class="headerlink" title="Young Collection 跨代引用"></a>Young Collection 跨代引用</h5><ul>
<li>新生代回收的跨代引用（老年代引用新生代）问题</li>
</ul>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/static20200608151211.png" srcset="/img/loading.gif" lazyload></p>
<ul>
<li>卡表与Remembered Set<ul>
<li>Remembered Set 存在于E中，用于保存新生代对象对应的脏卡<ul>
<li>脏卡：O被划分为多个区域（一个区域512K），如果该区域引用了新生代对象，则该区域被称为脏卡</li>
</ul>
</li>
</ul>
</li>
<li>在引用变更时通过post-write barried + dirty card queue</li>
<li>concurrent refinement threads 更新 Remembered Set</li>
</ul>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/static20200608151222.png" srcset="/img/loading.gif" lazyload></p>
<h5 id="Remark"><a href="#Remark" class="headerlink" title="Remark"></a>Remark</h5><p>重新标记阶段</p>
<p>在垃圾回收时，收集器处理对象的过程中</p>
<p>黑色：已被处理，需要保留的 灰色：正在处理中的 白色：还未处理的</p>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/static20200608151229.png" srcset="/img/loading.gif" lazyload></p>
<p>但是在<strong>并发标记过程中</strong>，有可能A被处理了以后未引用C，但该处理过程还未结束，在处理过程结束之前A引用了C，这时就会用到remark</p>
<p>过程如下</p>
<ul>
<li>之前C未被引用，这时A引用了C，就会给C加一个写屏障，写屏障的指令会被执行，将C放入一个队列当中，并将C变为 处理中 状态</li>
<li>在<strong>并发标记</strong>阶段结束以后，重新标记阶段会STW，然后将放在该队列中的对象重新处理，发现有强引用引用它，就会处理它</li>
</ul>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/20200608151239.png" srcset="/img/loading.gif" lazyload></p>
<h5 id="JDK-8u20-字符串去重"><a href="#JDK-8u20-字符串去重" class="headerlink" title="JDK 8u20 字符串去重"></a>JDK 8u20 字符串去重</h5><p>过程</p>
<ul>
<li>将所有新分配的字符串（底层是char[]）放入一个队列</li>
<li>当新生代回收时，G1并发检查是否有重复的字符串</li>
<li>如果字符串的值一样，就让他们<strong>引用同一个字符串对象</strong></li>
<li>注意，其与String.intern的区别<ul>
<li>intern关注的是字符串对象</li>
<li>字符串去重关注的是char[]</li>
<li>在JVM内部，使用了不同的字符串标</li>
</ul>
</li>
</ul>
<p>优点与缺点</p>
<ul>
<li>节省了大量内存</li>
<li>新生代回收时间略微增加，导致略微多占用CPU</li>
</ul>
<h5 id="JDK-8u40-并发标记类卸载"><a href="#JDK-8u40-并发标记类卸载" class="headerlink" title="JDK 8u40 并发标记类卸载"></a>JDK 8u40 并发标记类卸载</h5><p>在并发标记阶段结束以后，就能知道哪些类不再被使用。如果一个类加载器的所有类都不在使用，则卸载它所加载的所有类</p>
<h5 id="JDK-8u60-回收巨型对象"><a href="#JDK-8u60-回收巨型对象" class="headerlink" title="JDK 8u60 回收巨型对象"></a>JDK 8u60 回收巨型对象</h5><ul>
<li>一个对象大于region的一半时，就称为巨型对象</li>
<li>G1不会对巨型对象进行拷贝</li>
<li>回收时被优先考虑</li>
<li>G1会跟踪老年代所有incoming引用，如果老年代incoming引用为0的巨型对象就可以在新生代垃圾回收时处理掉</li>
</ul>
<p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/static20200608151249.png" srcset="/img/loading.gif" lazyload></p>
<h3 id="5-GC-调优"><a href="#5-GC-调优" class="headerlink" title="5. GC 调优"></a>5. GC 调优</h3><p>查看虚拟机参数命令</p>
<figure class="highlight pgsql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs pgsql">java -XX:+PrintFlagsFinal -<span class="hljs-keyword">version</span> | findstr &quot;GC&quot;<span class="hljs-keyword">Copy</span><br></code></pre></div></td></tr></table></figure>

<p>可以根据参数去查询具体的信息</p>
<h4 id="调优领域"><a href="#调优领域" class="headerlink" title="调优领域"></a>调优领域</h4><ul>
<li>内存</li>
<li>锁竞争</li>
<li>CPU占用</li>
<li>IO</li>
<li>GC</li>
</ul>
<h4 id="确定目标"><a href="#确定目标" class="headerlink" title="确定目标"></a>确定目标</h4><p>低延迟&#x2F;高吞吐量？ 选择合适的GC</p>
<ul>
<li>CMS G1 ZGC</li>
<li>ParallelGC</li>
<li>Zing</li>
</ul>
<h4 id="最快的GC是不发生GC"><a href="#最快的GC是不发生GC" class="headerlink" title="最快的GC是不发生GC"></a>最快的GC是不发生GC</h4><p>首先排除减少因为自身编写的代码而引发的内存问题</p>
<ul>
<li><p>查看Full GC前后的内存占用，考虑以下几个问题</p>
<ul>
<li><p>数据是不是太多？</p>
<figure class="highlight sql"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs sql">resultSet <span class="hljs-operator">=</span> statement.executeQuery(&quot;select * from 大表 &quot;)<br></code></pre></div></td></tr></table></figure>

<p>会将数据全部加载进内存，会导致GC频繁发生甚至Out Of Memory</p>
<p>可使用limit限制返回记录总数</p>
</li>
<li><p>数据表示是否太臃肿</p>
<ul>
<li>对象图 ：查询时尽量不要查询所有数据，仅查询需要的数据</li>
<li>对象大小 ：Integer 24字节与int 4字节</li>
</ul>
</li>
<li><p>是否存在内存泄漏</p>
<p>若使用java实现则尽量使用软引用或者弱引用创造相应的缓存对象</p>
<p>尽量不用java来实现，以减小垃圾回收压力</p>
<p>使用第三方缓存实现如：Redis</p>
</li>
</ul>
</li>
</ul>
<h4 id="新生代调优"><a href="#新生代调优" class="headerlink" title="新生代调优"></a>新生代调优</h4><ul>
<li>新生代的特点<ul>
<li>所有的new操作分配内存都是非常廉价的<ul>
<li>每个线程会在eden区分配一片私有的区域</li>
<li>TLAB  thread-local allocation buffffer</li>
</ul>
</li>
<li>死亡对象回收零代价</li>
<li>大部分对象用过即死（朝生夕死）</li>
<li>MInor GC 所用时间远小于Full GC</li>
</ul>
</li>
<li>新生代内存越大越好么？<ul>
<li>不是<ul>
<li>新生代内存太小：频繁触发Minor GC，会STW，会使得吞吐量下降</li>
<li>新生代内存太大：老年代内存占比有所降低，会更频繁地触发Full GC。而且触发Minor GC时，清理新生代所花费的时间会更长</li>
</ul>
</li>
<li>新生代内存设置为内容纳[并发量*(请求-响应)]的数据为宜</li>
</ul>
</li>
</ul>
<h4 id="幸存区调优"><a href="#幸存区调优" class="headerlink" title="幸存区调优"></a>幸存区调优</h4><ul>
<li>幸存区需要能够保存 <strong>当前活跃对象</strong>+<strong>需要晋升的对象</strong></li>
<li>晋升阈值配置得当，让长时间存活的对象尽快晋升</li>
</ul>
<h4 id="老年代调优"><a href="#老年代调优" class="headerlink" title="老年代调优"></a>老年代调优</h4><p>以 CMS 为例</p>
<ul>
<li><p>CMS 的老年代内存越大越好</p>
</li>
<li><p>先尝试不做调优，如果没有 Full GC 那么先尝试调优新生代</p>
</li>
<li><p>观察发生 Full GC 时老年代内存占用，将老年代内存预设调大 1&#x2F;4 ~ 1&#x2F;3</p>
</li>
</ul>
<h4 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h4><h5 id="案例1-Full-GC-和-Minor-GC频繁"><a href="#案例1-Full-GC-和-Minor-GC频繁" class="headerlink" title="案例1 Full GC 和 Minor GC频繁"></a>案例1 Full GC 和 Minor GC频繁</h5><p>分析：频繁发生GC说明存在空间紧张，进一步分析。如果是新生代空间紧张，比如业务高峰期来到，大量对象被创建，很快塞满了新生代的空间，导致幸存区对象晋升阈值降低，是的很多生存周期很短的对象晋升至老年代使得情况进一步恶化，Full GC也频繁发生。</p>
<p>解决思路：尝试增大新生代容量，内存充裕让MinorGC不那么频繁，同时幸存区空间和晋升阈值的增大，进一步让FullGC不那么频繁。</p>
<h5 id="案例2-请求高峰期发生-Full-GC，单次暂停时间特别长-CMS"><a href="#案例2-请求高峰期发生-Full-GC，单次暂停时间特别长-CMS" class="headerlink" title="案例2 请求高峰期发生 Full GC，单次暂停时间特别长(CMS)"></a>案例2 请求高峰期发生 Full GC，单次暂停时间特别长(CMS)</h5><p>分析：CMS暂停时间主要花在重新标记阶段，改阶段会扫描整个堆区，业务高峰期新生代对象较多。可能导致标记时间较长。</p>
<p>解决思路：在重新标记阶段来到之前进行一次新生代的垃圾回收-XX:+CMSScavengeBeforeRemark。</p>
<h5 id="案例3-老年代充裕情况下，发生-Full-GC-（CMS-jdk1-7）"><a href="#案例3-老年代充裕情况下，发生-Full-GC-（CMS-jdk1-7）" class="headerlink" title="案例3 老年代充裕情况下，发生 Full GC （CMS jdk1.7）"></a>案例3 老年代充裕情况下，发生 Full GC （CMS jdk1.7）</h5><p>分析：jdk1.8之前，方法区的实现是永久代。永久代的空间不足也会导致FullGC的发生。1.8之后使用元空间实现方法区，默认情况下使用的是操作系统的内存空间，空间容量一般比较充裕。</p>
<p>解决思路：增大永久代的初始值和最大值。</p>
<h2 id="四、类加载与字节码技术"><a href="#四、类加载与字节码技术" class="headerlink" title="四、类加载与字节码技术"></a>四、类加载与字节码技术</h2><p><img src="https://blog-chy.oss-cn-shenzhen.aliyuncs.com/static/image-20220227152916556.png" srcset="/img/loading.gif" lazyload alt="image-20220227152916556"></p>
<h3 id="1、类文件结构"><a href="#1、类文件结构" class="headerlink" title="1、类文件结构"></a>1、类文件结构</h3><p>首先获得.class字节码文件</p>
<p>方法：</p>
<ul>
<li>在文本文档里写入java代码（文件名与类名一致），将文件类型改为.java</li>
<li>java终端中，执行javac X:…\XXX.java</li>
</ul>
<p>以下是字节码文件</p>
<figure class="highlight apache"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs apache"><span class="hljs-attribute">0000000</span> ca fe ba be <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">34</span> <span class="hljs-number">00</span> <span class="hljs-number">23</span> <span class="hljs-number">0</span>a <span class="hljs-number">00</span> <span class="hljs-number">06</span> <span class="hljs-number">00</span> <span class="hljs-number">15</span> <span class="hljs-number">09</span> <br><span class="hljs-attribute">0000020</span> <span class="hljs-number">00</span> <span class="hljs-number">16</span> <span class="hljs-number">00</span> <span class="hljs-number">17</span> <span class="hljs-number">08</span> <span class="hljs-number">00</span> <span class="hljs-number">18</span> <span class="hljs-number">0</span>a <span class="hljs-number">00</span> <span class="hljs-number">19</span> <span class="hljs-number">00</span> <span class="hljs-number">1</span>a <span class="hljs-number">07</span> <span class="hljs-number">00</span> <span class="hljs-number">1</span>b <span class="hljs-number">07</span> <br><span class="hljs-attribute">0000040</span> <span class="hljs-number">00</span> <span class="hljs-number">1</span>c <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">06</span> <span class="hljs-number">3</span>c <span class="hljs-number">69</span> <span class="hljs-number">6</span>e <span class="hljs-number">69</span> <span class="hljs-number">74</span> <span class="hljs-number">3</span>e <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">03</span> <span class="hljs-number">28</span> <span class="hljs-number">29</span> <br><span class="hljs-attribute">0000060</span> <span class="hljs-number">56</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">04</span> <span class="hljs-number">43</span> <span class="hljs-number">6</span>f <span class="hljs-number">64</span> <span class="hljs-number">65</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>f <span class="hljs-number">4</span>c <span class="hljs-number">69</span> <span class="hljs-number">6</span>e <span class="hljs-number">65</span> <span class="hljs-number">4</span>e <br><span class="hljs-attribute">0000100</span> <span class="hljs-number">75</span> <span class="hljs-number">6</span>d <span class="hljs-number">62</span> <span class="hljs-number">65</span> <span class="hljs-number">72</span> <span class="hljs-number">54</span> <span class="hljs-number">61</span> <span class="hljs-number">62</span> <span class="hljs-number">6</span>c <span class="hljs-number">65</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">12</span> <span class="hljs-number">4</span>c <span class="hljs-number">6</span>f <span class="hljs-number">63</span> <br><span class="hljs-attribute">0000120</span> <span class="hljs-number">61</span> <span class="hljs-number">6</span>c <span class="hljs-number">56</span> <span class="hljs-number">61</span> <span class="hljs-number">72</span> <span class="hljs-number">69</span> <span class="hljs-number">61</span> <span class="hljs-number">62</span> <span class="hljs-number">6</span>c <span class="hljs-number">65</span> <span class="hljs-number">54</span> <span class="hljs-number">61</span> <span class="hljs-number">62</span> <span class="hljs-number">6</span>c <span class="hljs-number">65</span> <span class="hljs-number">01</span> <br><span class="hljs-attribute">0000140</span> <span class="hljs-number">00</span> <span class="hljs-number">04</span> <span class="hljs-number">74</span> <span class="hljs-number">68</span> <span class="hljs-number">69</span> <span class="hljs-number">73</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">1</span>d <span class="hljs-number">4</span>c <span class="hljs-number">63</span> <span class="hljs-number">6</span>e <span class="hljs-number">2</span>f <span class="hljs-number">69</span> <span class="hljs-number">74</span> <span class="hljs-number">63</span> <br><span class="hljs-attribute">0000160</span> <span class="hljs-number">61</span> <span class="hljs-number">73</span> <span class="hljs-number">74</span> <span class="hljs-number">2</span>f <span class="hljs-number">6</span>a <span class="hljs-number">76</span> <span class="hljs-number">6</span>d <span class="hljs-number">2</span>f <span class="hljs-number">74</span> <span class="hljs-number">35</span> <span class="hljs-number">2</span>f <span class="hljs-number">48</span> <span class="hljs-number">65</span> <span class="hljs-number">6</span>c <span class="hljs-number">6</span>c <span class="hljs-number">6</span>f <br><span class="hljs-attribute">0000200</span> <span class="hljs-number">57</span> <span class="hljs-number">6</span>f <span class="hljs-number">72</span> <span class="hljs-number">6</span>c <span class="hljs-number">64</span> <span class="hljs-number">3</span>b <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">04</span> <span class="hljs-number">6</span>d <span class="hljs-number">61</span> <span class="hljs-number">69</span> <span class="hljs-number">6</span>e <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">16</span> <br><span class="hljs-attribute">0000220</span> <span class="hljs-number">28</span> <span class="hljs-number">5</span>b <span class="hljs-number">4</span>c <span class="hljs-number">6</span>a <span class="hljs-number">61</span> <span class="hljs-number">76</span> <span class="hljs-number">61</span> <span class="hljs-number">2</span>f <span class="hljs-number">6</span>c <span class="hljs-number">61</span> <span class="hljs-number">6</span>e <span class="hljs-number">67</span> <span class="hljs-number">2</span>f <span class="hljs-number">53</span> <span class="hljs-number">74</span> <span class="hljs-number">72</span> <br><span class="hljs-attribute">0000240</span> <span class="hljs-number">69</span> <span class="hljs-number">6</span>e <span class="hljs-number">67</span> <span class="hljs-number">3</span>b <span class="hljs-number">29</span> <span class="hljs-number">56</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">04</span> <span class="hljs-number">61</span> <span class="hljs-number">72</span> <span class="hljs-number">67</span> <span class="hljs-number">73</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">13</span> <br><span class="hljs-attribute">0000260</span> <span class="hljs-number">5</span>b <span class="hljs-number">4</span>c <span class="hljs-number">6</span>a <span class="hljs-number">61</span> <span class="hljs-number">76</span> <span class="hljs-number">61</span> <span class="hljs-number">2</span>f <span class="hljs-number">6</span>c <span class="hljs-number">61</span> <span class="hljs-number">6</span>e <span class="hljs-number">67</span> <span class="hljs-number">2</span>f <span class="hljs-number">53</span> <span class="hljs-number">74</span> <span class="hljs-number">72</span> <span class="hljs-number">69</span> <br><span class="hljs-attribute">0000300</span> <span class="hljs-number">6</span>e <span class="hljs-number">67</span> <span class="hljs-number">3</span>b <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">10</span> <span class="hljs-number">4</span>d <span class="hljs-number">65</span> <span class="hljs-number">74</span> <span class="hljs-number">68</span> <span class="hljs-number">6</span>f <span class="hljs-number">64</span> <span class="hljs-number">50</span> <span class="hljs-number">61</span> <span class="hljs-number">72</span> <span class="hljs-number">61</span> <br><span class="hljs-attribute">0000320</span> <span class="hljs-number">6</span>d <span class="hljs-number">65</span> <span class="hljs-number">74</span> <span class="hljs-number">65</span> <span class="hljs-number">72</span> <span class="hljs-number">73</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>a <span class="hljs-number">53</span> <span class="hljs-number">6</span>f <span class="hljs-number">75</span> <span class="hljs-number">72</span> <span class="hljs-number">63</span> <span class="hljs-number">65</span> <span class="hljs-number">46</span> <br><span class="hljs-attribute">0000340</span> <span class="hljs-number">69</span> <span class="hljs-number">6</span>c <span class="hljs-number">65</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>f <span class="hljs-number">48</span> <span class="hljs-number">65</span> <span class="hljs-number">6</span>c <span class="hljs-number">6</span>c <span class="hljs-number">6</span>f <span class="hljs-number">57</span> <span class="hljs-number">6</span>f <span class="hljs-number">72</span> <span class="hljs-number">6</span>c <span class="hljs-number">64</span><br><span class="hljs-attribute">0000360</span> <span class="hljs-number">2</span>e <span class="hljs-number">6</span>a <span class="hljs-number">61</span> <span class="hljs-number">76</span> <span class="hljs-number">61</span> <span class="hljs-number">0</span>c <span class="hljs-number">00</span> <span class="hljs-number">07</span> <span class="hljs-number">00</span> <span class="hljs-number">08</span> <span class="hljs-number">07</span> <span class="hljs-number">00</span> <span class="hljs-number">1</span>d <span class="hljs-number">0</span>c <span class="hljs-number">00</span> <span class="hljs-number">1</span>e <br><span class="hljs-attribute">0000400</span> <span class="hljs-number">00</span> <span class="hljs-number">1</span>f <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>b <span class="hljs-number">68</span> <span class="hljs-number">65</span> <span class="hljs-number">6</span>c <span class="hljs-number">6</span>c <span class="hljs-number">6</span>f <span class="hljs-number">20</span> <span class="hljs-number">77</span> <span class="hljs-number">6</span>f <span class="hljs-number">72</span> <span class="hljs-number">6</span>c <span class="hljs-number">64</span> <br><span class="hljs-attribute">0000420</span> <span class="hljs-number">07</span> <span class="hljs-number">00</span> <span class="hljs-number">20</span> <span class="hljs-number">0</span>c <span class="hljs-number">00</span> <span class="hljs-number">21</span> <span class="hljs-number">00</span> <span class="hljs-number">22</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">1</span>b <span class="hljs-number">63</span> <span class="hljs-number">6</span>e <span class="hljs-number">2</span>f <span class="hljs-number">69</span> <span class="hljs-number">74</span> <br><span class="hljs-attribute">0000440</span> <span class="hljs-number">63</span> <span class="hljs-number">61</span> <span class="hljs-number">73</span> <span class="hljs-number">74</span> <span class="hljs-number">2</span>f <span class="hljs-number">6</span>a <span class="hljs-number">76</span> <span class="hljs-number">6</span>d <span class="hljs-number">2</span>f <span class="hljs-number">74</span> <span class="hljs-number">35</span> <span class="hljs-number">2</span>f <span class="hljs-number">48</span> <span class="hljs-number">65</span> <span class="hljs-number">6</span>c <span class="hljs-number">6</span>c <br><span class="hljs-attribute">0000460</span> <span class="hljs-number">6</span>f <span class="hljs-number">57</span> <span class="hljs-number">6</span>f <span class="hljs-number">72</span> <span class="hljs-number">6</span>c <span class="hljs-number">64</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">10</span> <span class="hljs-number">6</span>a <span class="hljs-number">61</span> <span class="hljs-number">76</span> <span class="hljs-number">61</span> <span class="hljs-number">2</span>f <span class="hljs-number">6</span>c <span class="hljs-number">61</span> <br><span class="hljs-attribute">0000500</span> <span class="hljs-number">6</span>e <span class="hljs-number">67</span> <span class="hljs-number">2</span>f <span class="hljs-number">4</span>f <span class="hljs-number">62</span> <span class="hljs-number">6</span>a <span class="hljs-number">65</span> <span class="hljs-number">63</span> <span class="hljs-number">74</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">10</span> <span class="hljs-number">6</span>a <span class="hljs-number">61</span> <span class="hljs-number">76</span> <span class="hljs-number">61</span> <br><span class="hljs-attribute">0000520</span> <span class="hljs-number">2</span>f <span class="hljs-number">6</span>c <span class="hljs-number">61</span> <span class="hljs-number">6</span>e <span class="hljs-number">67</span> <span class="hljs-number">2</span>f <span class="hljs-number">53</span> <span class="hljs-number">79</span> <span class="hljs-number">73</span> <span class="hljs-number">74</span> <span class="hljs-number">65</span> <span class="hljs-number">6</span>d <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">03</span> <span class="hljs-number">6</span>f <br><span class="hljs-attribute">0000540</span> <span class="hljs-number">75</span> <span class="hljs-number">74</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">15</span> <span class="hljs-number">4</span>c <span class="hljs-number">6</span>a <span class="hljs-number">61</span> <span class="hljs-number">76</span> <span class="hljs-number">61</span> <span class="hljs-number">2</span>f <span class="hljs-number">69</span> <span class="hljs-number">6</span>f <span class="hljs-number">2</span>f <span class="hljs-number">50</span> <span class="hljs-number">72</span> <br><span class="hljs-attribute">0000560</span> <span class="hljs-number">69</span> <span class="hljs-number">6</span>e <span class="hljs-number">74</span> <span class="hljs-number">53</span> <span class="hljs-number">74</span> <span class="hljs-number">72</span> <span class="hljs-number">65</span> <span class="hljs-number">61</span> <span class="hljs-number">6</span>d <span class="hljs-number">3</span>b <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">13</span> <span class="hljs-number">6</span>a <span class="hljs-number">61</span> <span class="hljs-number">76</span> <br><span class="hljs-attribute">0000600</span> <span class="hljs-number">61</span> <span class="hljs-number">2</span>f <span class="hljs-number">69</span> <span class="hljs-number">6</span>f <span class="hljs-number">2</span>f <span class="hljs-number">50</span> <span class="hljs-number">72</span> <span class="hljs-number">69</span> <span class="hljs-number">6</span>e <span class="hljs-number">74</span> <span class="hljs-number">53</span> <span class="hljs-number">74</span> <span class="hljs-number">72</span> <span class="hljs-number">65</span> <span class="hljs-number">61</span> <span class="hljs-number">6</span>d <br><span class="hljs-attribute">0000620</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">07</span> <span class="hljs-number">70</span> <span class="hljs-number">72</span> <span class="hljs-number">69</span> <span class="hljs-number">6</span>e <span class="hljs-number">74</span> <span class="hljs-number">6</span>c <span class="hljs-number">6</span>e <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">15</span> <span class="hljs-number">28</span> <span class="hljs-number">4</span>c <span class="hljs-number">6</span>a <br><span class="hljs-attribute">0000640</span> <span class="hljs-number">61</span> <span class="hljs-number">76</span> <span class="hljs-number">61</span> <span class="hljs-number">2</span>f <span class="hljs-number">6</span>c <span class="hljs-number">61</span> <span class="hljs-number">6</span>e <span class="hljs-number">67</span> <span class="hljs-number">2</span>f <span class="hljs-number">53</span> <span class="hljs-number">74</span> <span class="hljs-number">72</span> <span class="hljs-number">69</span> <span class="hljs-number">6</span>e <span class="hljs-number">67</span> <span class="hljs-number">3</span>b <br><span class="hljs-attribute">0000660</span> <span class="hljs-number">29</span> <span class="hljs-number">56</span> <span class="hljs-number">00</span> <span class="hljs-number">21</span> <span class="hljs-number">00</span> <span class="hljs-number">05</span> <span class="hljs-number">00</span> <span class="hljs-number">06</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">02</span> <span class="hljs-number">00</span> <span class="hljs-number">01</span> <br><span class="hljs-attribute">0000700</span> <span class="hljs-number">00</span> <span class="hljs-number">07</span> <span class="hljs-number">00</span> <span class="hljs-number">08</span> <span class="hljs-number">00</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">09</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">2</span>f <span class="hljs-number">00</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">01</span> <br><span class="hljs-attribute">0000720</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">05</span> <span class="hljs-number">2</span>a b7 <span class="hljs-number">00</span> <span class="hljs-number">01</span> b1 <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">02</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>a <span class="hljs-number">00</span> <br><span class="hljs-attribute">0000740</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">06</span> <span class="hljs-number">00</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">04</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>b <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>c <span class="hljs-number">00</span> <br><span class="hljs-attribute">0000760</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">05</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>c <span class="hljs-number">00</span> <span class="hljs-number">0</span>d <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">09</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>e <span class="hljs-number">00</span> <br><span class="hljs-attribute">0001000</span> <span class="hljs-number">0</span>f <span class="hljs-number">00</span> <span class="hljs-number">02</span> <span class="hljs-number">00</span> <span class="hljs-number">09</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">37</span> <span class="hljs-number">00</span> <span class="hljs-number">02</span> <span class="hljs-number">00</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <br><span class="hljs-attribute">0001020</span> <span class="hljs-number">09</span> b2 <span class="hljs-number">00</span> <span class="hljs-number">02</span> <span class="hljs-number">12</span> <span class="hljs-number">03</span> b6 <span class="hljs-number">00</span> <span class="hljs-number">04</span> b1 <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">02</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>a <br><span class="hljs-attribute">0001040</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>a <span class="hljs-number">00</span> <span class="hljs-number">02</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">06</span> <span class="hljs-number">00</span> <span class="hljs-number">08</span> <span class="hljs-number">00</span> <span class="hljs-number">07</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>b <br><span class="hljs-attribute">0001060</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">0</span>c <span class="hljs-number">00</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">09</span> <span class="hljs-number">00</span> <span class="hljs-number">10</span> <span class="hljs-number">00</span> <span class="hljs-number">11</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <br><span class="hljs-attribute">0001100</span> <span class="hljs-number">00</span> <span class="hljs-number">12</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">05</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">10</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">01</span> <span class="hljs-number">00</span> <span class="hljs-number">13</span> <span class="hljs-number">00</span> <br><span class="hljs-attribute">0001120</span> <span class="hljs-number">00</span> <span class="hljs-number">00</span> <span class="hljs-number">02</span> <span class="hljs-number">00</span> <span class="hljs-number">14</span>Copy<br></code></pre></div></td></tr></table></figure>

<p>根据 JVM 规范，<strong>类文件结构</strong>如下</p>
<figure class="highlight abnf"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs abnf">u4 			 magic<br>u2             minor_version<span class="hljs-comment">;    </span><br>u2             major_version<span class="hljs-comment">;    </span><br>u2             constant_pool_count<span class="hljs-comment">;    </span><br>cp_info        constant_pool[constant_pool_count-<span class="hljs-number">1</span>]<span class="hljs-comment">;    </span><br>u2             access_flags<span class="hljs-comment">;    </span><br>u2             this_class<span class="hljs-comment">;    </span><br>u2             super_class<span class="hljs-comment">;   </span><br>u2             interfaces_count<span class="hljs-comment">;    </span><br>u2             interfaces[interfaces_count]<span class="hljs-comment">;   </span><br>u2             fields_count<span class="hljs-comment">;    </span><br>field_info     fields[fields_count]<span class="hljs-comment">;   </span><br>u2             methods_count<span class="hljs-comment">;    </span><br>method_info    methods[methods_count]<span class="hljs-comment">;    </span><br>u2             attributes_count<span class="hljs-comment">;    </span><br>attribute_info attributes[attributes_count]<span class="hljs-comment">;Copy</span><br></code></pre></div></td></tr></table></figure>

<h4 id="魔数"><a href="#魔数" class="headerlink" title="魔数"></a>魔数</h4><p>u4 magic</p>
<p>对应字节码文件的0~3个字节</p>
<p>0000000 <strong>ca fe ba be</strong> 00 00 00 34 00 23 0a 00 06 00 15 09   (cafe baby)</p>
<h4 id="版本"><a href="#版本" class="headerlink" title="版本"></a>版本</h4><p>u2 minor_version;</p>
<p>u2 major_version;</p>
<p>0000000 ca fe ba be <strong>00 00 00 34</strong> 00 23 0a 00 06 00 15 09</p>
<p>34H &#x3D; 52，代表JDK8</p>
<h4 id="字节码常量池分析"><a href="#字节码常量池分析" class="headerlink" title="字节码常量池分析"></a>字节码常量池分析</h4><p>详情见资料文件</p>
<h3 id="2、字节码指令"><a href="#2、字节码指令" class="headerlink" title="2、字节码指令"></a>2、字节码指令</h3><h4 id="2-1-入门"><a href="#2-1-入门" class="headerlink" title="2.1 入门"></a>2.1 入门</h4><p>接着上一节，研究一下两组字节码指令，一个是public cn.itcast.jvm.t5.HelloWorld(); 构造方法的字节码指令</p>
<p><code>2a b7 00 01 b1</code></p>
<ol>
<li><p>2a &#x3D;&gt; <em>aload_0</em> 加载 slot 0 的局部变量，即 this，做为下面的 <em>invokespecial</em> 构造方法调用的参数</p>
</li>
<li><p>b7 &#x3D;&gt; <em>invokespecial</em> 预备调用构造方法，哪个方法呢？</p>
</li>
<li><p>00 01 引用常量池中 #1 项，即【 Method java&#x2F;lang&#x2F;Object.”<init>“:()V 】 </p>
</li>
<li><p>b1 表示返回</p>
</li>
</ol>
<p>另一个是 public static void main(java.lang.String[]); 主方法的字节码指令</p>
<p><code>b2 00 02 12 03 b6 00 04 b1 </code></p>
<ol>
<li><p>b2 &#x3D;&gt; <em>getstatic</em> 用来加载静态变量，哪个静态变量呢？</p>
</li>
<li><p>00 02 引用常量池中 #2 项，即【Field java&#x2F;lang&#x2F;System.out:Ljava&#x2F;io&#x2F;PrintStream;】 </p>
</li>
<li><p>12 &#x3D;&gt; <em>ldc</em> 加载参数，哪个参数呢？</p>
</li>
<li><p>03 引用常量池中 #3 项，即 【String hello world】 </p>
</li>
<li><p>b6 &#x3D;&gt; <em>invokevirtual</em> 预备调用成员方法，哪个方法呢？</p>
</li>
<li><p>00 04 引用常量池中 #4 项，即【Method java&#x2F;io&#x2F;PrintStream.println:(Ljava&#x2F;lang&#x2F;String;)V】 </p>
</li>
<li><p>b1 表示返回</p>
</li>
</ol>
<p>可参考</p>
<p><a target="_blank" rel="noopener" href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5">https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5</a></p>
<h4 id="2-2-javap工具"><a href="#2-2-javap工具" class="headerlink" title="2.2 javap工具"></a>2.2 javap工具</h4><p>Oracle 提供了 <strong>javap</strong> 工具来反编译 class 文件</p>
<figure class="highlight bash"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs bash">Classfile /D:/Program Files/JetBrains/workspace/jvm/out/production/jvm/t5/HelloWorld.class<br>  Last modified 2022-2-21; size 539 bytes<br>  MD5 checksum 7dede3a2ea79b7095ea4e895d2a766b1<br>  Compiled from <span class="hljs-string">&quot;HelloWorld.java&quot;</span><br>public class t5.HelloWorld<br>  minor version: 0<br>  major version: 52<br>  flags: ACC_PUBLIC, ACC_SUPER<br>Constant pool:<br>   <span class="hljs-comment">#1 = Methodref          #6.#20         // java/lang/Object.&quot;&lt;init&gt;&quot;:()V</span><br>   <span class="hljs-comment">#2 = Fieldref           #21.#22        // java/lang/System.out:Ljava/io/PrintStream;</span><br>   <span class="hljs-comment">#3 = String             #23            // hello world</span><br>   <span class="hljs-comment">#4 = Methodref          #24.#25        // java/io/PrintStream.println:(Ljava/lang/String;)V</span><br>   <span class="hljs-comment">#5 = Class              #26            // t5/HelloWorld</span><br>   <span class="hljs-comment">#6 = Class              #27            // java/lang/Object</span><br>   <span class="hljs-comment">#7 = Utf8               &lt;init&gt;</span><br>   <span class="hljs-comment">#8 = Utf8               ()V</span><br>   <span class="hljs-comment">#9 = Utf8               Code</span><br>  <span class="hljs-comment">#10 = Utf8               LineNumberTable</span><br>  <span class="hljs-comment">#11 = Utf8               LocalVariableTable</span><br>  <span class="hljs-comment">#12 = Utf8               this</span><br>  <span class="hljs-comment">#13 = Utf8               Lt5/HelloWorld;</span><br>  <span class="hljs-comment">#14 = Utf8               main</span><br>  <span class="hljs-comment">#15 = Utf8               ([Ljava/lang/String;)V</span><br>  <span class="hljs-comment">#16 = Utf8               args</span><br>  <span class="hljs-comment">#17 = Utf8               [Ljava/lang/String;</span><br>  <span class="hljs-comment">#18 = Utf8               SourceFile</span><br>  <span class="hljs-comment">#19 = Utf8               HelloWorld.java</span><br>  <span class="hljs-comment">#20 = NameAndType        #7:#8          // &quot;&lt;init&gt;&quot;:()V</span><br>  <span class="hljs-comment">#21 = Class              #28            // java/lang/System</span><br>  <span class="hljs-comment">#22 = NameAndType        #29:#30        // out:Ljava/io/PrintStream;</span><br>  <span class="hljs-comment">#23 = Utf8               hello world</span><br>  <span class="hljs-comment">#24 = Class              #31            // java/io/PrintStream</span><br>  <span class="hljs-comment">#25 = NameAndType        #32:#33        // println:(Ljava/lang/String;)V</span><br>  <span class="hljs-comment">#26 = Utf8               t5/HelloWorld</span><br>  <span class="hljs-comment">#27 = Utf8               java/lang/Object</span><br>  <span class="hljs-comment">#28 = Utf8               java/lang/System</span><br>  <span class="hljs-comment">#29 = Utf8               out</span><br>  <span class="hljs-comment">#30 = Utf8               Ljava/io/PrintStream;</span><br>  <span class="hljs-comment">#31 = Utf8               java/io/PrintStream</span><br>  <span class="hljs-comment">#32 = Utf8               println</span><br>  <span class="hljs-comment">#33 = Utf8               (Ljava/lang/String;)V</span><br>&#123;<br>  public t5.HelloWorld();<br>    descriptor: ()V<br>    flags: ACC_PUBLIC<br>    Code:<br>      stack=1, locals=1, args_size=1 <span class="hljs-comment">#stack-&gt;栈的深度  locals-&gt;局部变量表的长度 args_size-&gt;参数长度</span><br>         0: aload_0<br>         1: invokespecial <span class="hljs-comment">#1                  // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V</span><br>         4: <span class="hljs-built_in">return</span>   <span class="hljs-comment"># 数字0,1,4代表字节码中的行号</span><br>      LineNumberTable:<br>        line 4: 0  <span class="hljs-comment"># 7代表java源代码行号 0代表字节码行号</span><br>      LocalVariableTable:  <span class="hljs-comment">#本地变量表</span><br>        Start  Length  Slot  Name   Signature<br>            0       5     0  this   Lt5/HelloWorld;  <span class="hljs-comment">#length表示变量作用范围</span><br><br>  public static void main(java.lang.String[]);<br>    descriptor: ([Ljava/lang/String;)V<br>    flags: ACC_PUBLIC, ACC_STATIC<br>    Code:<br>      stack=2, locals=1, args_size=1<br>         0: getstatic     <span class="hljs-comment">#2                  // Field java/lang/System.out:Ljava/io/PrintStream;</span><br>         3: ldc           <span class="hljs-comment">#3                  // String hello world</span><br>         5: invokevirtual <span class="hljs-comment">#4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V</span><br>         8: <span class="hljs-built_in">return</span><br>      LineNumberTable:<br>        line 6: 0<br>        line 7: 8<br>      LocalVariableTable:<br>        Start  Length  Slot  Name   Signature<br>            0       9     0  args   [Ljava/lang/String;<br>&#125;<br>SourceFile: <span class="hljs-string">&quot;HelloWorld.java&quot;</span><br></code></pre></div></td></tr></table></figure>

<h4 id="2-3-图解方法执行流程"><a href="#2-3-图解方法执行流程" class="headerlink" title="2.3 图解方法执行流程"></a>2.3 图解方法执行流程</h4><p>代码</p>
<figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo3_1</span> &#123;    <br>	<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;        <br>		<span class="hljs-type">int</span> <span class="hljs-variable">a</span> <span class="hljs-operator">=</span> <span class="hljs-number">10</span>;        <span class="hljs-comment">// 较小的数字并不是存储在常量池中和方法的字节码指令存在一起</span><br>		<span class="hljs-type">int</span> <span class="hljs-variable">b</span> <span class="hljs-operator">=</span> Short.MAX_VALUE + <span class="hljs-number">1</span>;   <span class="hljs-comment">// 数字范围超过了整数的最大值 存储在常量池中</span><br>		<span class="hljs-type">int</span> <span class="hljs-variable">c</span> <span class="hljs-operator">=</span> a + b;        <br>		System.out.println(c);   <br>    &#125; <br>&#125;<br></code></pre></div></td></tr></table></figure>


            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/Java/">Java</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/JVM/">JVM</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客所有文章除特别声明外，均采用 <a target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/02/27/Java%E5%BC%82%E5%B8%B8/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">Java异常</span>
                        <span class="visible-mobile">Previous</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/02/25/%E6%88%91%E7%9A%84%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/">
                        <span class="hidden-mobile">我的博客搭建解决方案</span>
                        <span class="visible-mobile">Next</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
              <!-- Comments -->
              <article class="comments" id="comments" lazyload>
                
                  
                
                

              </article>
            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;TOC</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">Search</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">keyword</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
     <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
  </div>
  
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  <script  src="/js/local-search.js" ></script>



  
    <script  src="/js/img-lazyload.js" ></script>
  



  



  
    <script  src="https://cdn.jsdelivr.net/npm/tocbot@4/dist/tocbot.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4/anchor.min.js" ></script>
  
  
    <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js" ></script>
  



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
        typing(title);
      
    })(window, document);
  </script>















<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>


</body>
</html>
